/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://code.google.com/p/dylab/

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

#ifndef __dylab_String_h__
#define __dylab_String_h__

//===========================================================================================
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>

//===========================================================================================
#include <dylab/utils/types/types.h>

//===========================================================================================
namespace dylab {

    /** standard String class
     */    
    class DYLAB_EXPORT String
        : public std::string
    {
    public:
        static const String EMPTY;

    public:

        /**
		 * Formats the given argument.
         */
        template <typename T>
        static String fmt(const T & _value)
                { return (boost::format("%1%") % _value).str(); }

        /**
		 * Formats the given arguments according to the the string.
		 * For all the formating characters please refer to the boost::format documantation.
         */
        template <typename _ArgT>
        static inline String fmt(const String & _fmt, const _ArgT & _value)
                { return (boost::format(_fmt) % _value).str(); }

        /**
		 * Formats the given arguments according to the the string.
		 * For all the formating characters please refer to the boost::format documantation.
         */
        template <typename _ArgT1, typename _ArgT2>
        static inline String fmt(const String & _fmt, const _ArgT1 & _value1, const _ArgT2 & _value2)
                { return (boost::format(_fmt) % _value1 % _value2).str(); }

        /**
		 * Formats the given arguments according to the the string.
		 * For all the formating characters please refer to the boost::format documantation.
         */
        template <typename _ArgT1, typename _ArgT2, typename _ArgT3>
        static inline String fmt(const String & _fmt, const _ArgT1 & _value1, const _ArgT2 & _value2, 
			const _ArgT3 & _value3)
                { return (boost::format(_fmt) % _value1 % _value2 % _value3).str(); }

        /**
		 * Formats the given arguments according to the the string.
		 * For all the formating characters please refer to the boost::format documantation.
         */
        template <typename _ArgT1, typename _ArgT2, typename _ArgT3, typename _ArgT4>
        static inline String fmt(const String & _fmt, const _ArgT1 & _value1, const _ArgT2 & _value2, 
			const _ArgT3 & _value3, const _ArgT4 & _value4)
                { return (boost::format(_fmt) % _value1 % _value2 % _value3 % _value4).str(); }

        /**
		 * Formats the given arguments according to the the string.
		 * For all the formating characters please refer to the boost::format documantation.
         */
        template <typename _ArgT1, typename _ArgT2, typename _ArgT3, typename _ArgT4, typename _ArgT5>
        static inline String fmt(const String & _fmt, const _ArgT1 & _value1, const _ArgT2 & _value2, 
			const _ArgT3 & _value3, const _ArgT4 & _value4, const _ArgT5 & _value5)
                { return (boost::format(_fmt) % _value1 % _value2 % _value3 % _value4 % _value5).str(); }

        /**
		 * Formats the given arguments according to the the string.
		 * For all the formating characters please refer to the boost::format documantation.
         */
        template <typename _ArgT1, typename _ArgT2, typename _ArgT3, typename _ArgT4, typename _ArgT5, typename _ArgT6>
        static inline String fmt(const String & _fmt, const _ArgT1 & _value1, const _ArgT2 & _value2, 
			const _ArgT3 & _value3, const _ArgT4 & _value4, const _ArgT5 & _value5, const _ArgT6 & _value6)
                { return (boost::format(_fmt) % _value1 % _value2 % _value3 % _value4 % _value5 % _value6).str(); }

        /**
        */
        static String getFirstLeftPart(const String & _str, const String & _separator);

        /**
        */
        static String getLastLeftPart(const String & _str, const String & _separator);

        /**
        */
        static String getFirstRightPart(const String & _str, const String & _separator);

        /**
        */
        static String getLastRightPart(const String & _str, const String & _separator);

    public:

        /**
        */
        String() 
                { }

        /**
        */
        String(const char * _str)
            : std::string(_str)
                { }

        /**
        */
        String(const std::string & _source) 
            : std::string(_source)
                { }

        /**
        */
        String(const String & _source) 
            : std::string(_source)
                { }

        /**
        */
        bool isEmpty() const
                { return (*this) == EMPTY; }

        /**
        */
        String getFirstLeftPart(const String & _separator) const
                { return getFirstLeftPart(*this, _separator); }

        /**
        */
        String getFirstRightPart(const String & _separator) const
                { return getFirstRightPart(*this, _separator); }

        /**
        */
        String getLastLeftPart(const String & _separator) const
                { return getLastLeftPart(*this, _separator); }

        /**
        */
        String getLastRightPart(const String & _separator) const
                { return getLastRightPart(*this, _separator); }

        /**
        */
        bool contains(const String & _s) const
                { return find(_s) != String::npos; }

        /**
        */
        String getFirstSection(const String & _leftBorder, const String & _rightBorder) const
                { return getFirstRightPart(_leftBorder).getFirstLeftPart(_rightBorder); }

        /**
        */
        String & replaceFirstSection(const String & _old, const String & _new)
                { 
                    boost::replace_first(*this, _old, _new);
                    return *this;
                }

        /**
        */
        String & trim()
                { 
                    boost::trim(*this); 
                    return *this;
                }

        //===========================================================================================
        // converters
        //===========================================================================================

        /**
        */
        template <typename T>
        T parse() const
                { return TypeParser::parse<T>(*this); }

        /**
        */
        template <typename T>
        T parse(const T & _defaultValue)
                { return TypeParser::parse<T>(*this, _defaultValue); }

        //===========================================================================================
        // operators
        //===========================================================================================

        /**
        */
        template <typename T>
        boost::format operator % (const T & _value)
                { return boost::format(*this) % _value; }
    };

    //===========================================================================================    
    template <typename T>
    boost::format operator % (const String & _str, const T _value)
            { return boost::format(_str) % _value; }
}

//===========================================================================================
// helper macro for getting general variable & object info as a string
#define DYLAB_EXP_INFO(e)		String::fmt("%1% = '%2%'", #e, e)
#define DYLAB_OBJEXP_INFO(o)    String::fmt("%1% = '%2%' (%3%)", #o, o, typeid(o).name())

//===========================================================================================
namespace stdext {
    // hash String to size_t _value (for stdext::hash_map<String, *>)
    inline size_t hash_value(const dylab::String & _str)
	{	
        typedef dylab::String::size_type SizeT;

	    size_t val = (size_t)0xdeadbeef;
	    SizeT size = _str.size();
	    if (0 < size)
		{	// add one or more elements
		    SizeT stride = (size / 16) + 1;
		    size -= stride;	// protect against size near _str.max_size()
		    for(SizeT i = 0; i <= size; i += stride)
			    val += (size_t)_str[i];
        }
	    return (val);
	}
}

//===========================================================================================
#endif // __dylab_String_h__
